<template>
  <div class="database-info" v-loading="loading">
    <div class="base-info" v-if="database">
      <div class="database-meta">
        <div>
          <span class="database--name">{{ database.name }}</span>
        </div>
        <div>
          <span>编码:</span>
          <span>{{ charset }}</span>
        </div>
        <el-tooltip placement="left" effect="dark" :content="serverInfo">
          <el-icon>
            <info-filled></info-filled>
          </el-icon>
        </el-tooltip>
      </div>
      <div class="toolbar">
        <el-button @click="onExportDatabaseDoc" size="small" style="margin-right: 10px;">生成文档</el-button>
        <el-button @click="onExportDatabase" size="small" style="margin-right: 10px;">导出数据</el-button>
        <el-input v-model.trim.lazy="filters.name" placeholder="名称过滤" size="small" style="margin-right: 10px"
                  clearable></el-input>
        <el-button size="small" @click="loadInfo()" title="刷新">
          <el-icon>
            <refresh></refresh>
          </el-icon>
        </el-button>
      </div>
    </div>
    <el-tabs class="main-tab" tab-position="left" v-if="database">
      <el-tab-pane :label="`表 (${tables.rowsAffected || 0})`">
        <splitpanes horizontal>
          <pane>
            <el-table :data="computedTable" height="100%" @row-click="onTableRowSelect" size="small"
                      @row-dblclick="doOpenDataTable" border stripe highlight-current-row ref="tables"
                      @select="onTableSelect"
                      @select-all="onTableSelectAll">
              <el-table-column type="selection" align="center" width="60"></el-table-column>
              <el-table-column label="序号" type="index" align="center" width="60"></el-table-column>
              <el-table-column label="名称" prop="TABLE_NAME"></el-table-column>
              <el-table-column label="类型" prop="TABLE_TYPE" width="100"></el-table-column>
              <el-table-column label="引擎" prop="ENGINE" width="100"></el-table-column>
              <el-table-column label="行格式" prop="ROW_FORMAT" width="100"></el-table-column>
              <el-table-column label="行数" prop="TABLE_ROWS" width="100"></el-table-column>
              <el-table-column label="字符集" prop="TABLE_COLLATION" width="200"></el-table-column>
              <el-table-column label="备注" prop="TABLE_COMMENT"></el-table-column>
            </el-table>
          </pane>
          <pane>
            <el-tabs @tab-click="onTableTabClick" v-model="tableTabName" tab-position="top">
              <el-tab-pane label="表格视图" name="table">
                <table-columns :table="selectedTable.TABLE_NAME" />
              </el-tab-pane>
              <el-tab-pane label="代码视图" name="code">
                <cm readonly :code="tableDefinition" v-if="tableDefinition" />
              </el-tab-pane>
            </el-tabs>
          </pane>
        </splitpanes>
      </el-tab-pane>
      <el-tab-pane :label="`视图 (${views.rowsAffected || 0})`">
        <splitpanes horizontal>
          <pane>
            <el-table :data="computedView" height="100%" @row-click="(row) => (selectedView = row)" size="small"
                      @row-dblclick="doOpenDataTable" border stripe highlight-current-row>
              <el-table-column label="序号" type="index" align="center" width="60"></el-table-column>
              <el-table-column label="名称" prop="TABLE_NAME" width="200"></el-table-column>
              <el-table-column label="用户" prop="DEFINER" width="120"></el-table-column>
              <el-table-column label="定义" prop="VIEW_DEFINITION" class-name="auto-ellipsis"></el-table-column>
            </el-table>
          </pane>
          <pane>
            <cm readonly :code="selectedView.VIEW_DEFINITION" v-if="selectedView.VIEW_DEFINITION" />
          </pane>
        </splitpanes>
      </el-tab-pane>
      <el-tab-pane :label="`函数 (${functions.rowsAffected || 0})`">
        <splitpanes horizontal>
          <pane>
            <el-table :data="computedFunction" height="100%" @row-click="(row) => (selectedFunction = row)" size="small"
                      border stripe highlight-current-row>
              <el-table-column label="序号" type="index" align="center" width="60"></el-table-column>
              <el-table-column label="名称" prop="ROUTINE_NAME" width="200"></el-table-column>
              <el-table-column label="类型" prop="ROUTINE_TYPE" width="80"></el-table-column>
              <el-table-column label="用户" prop="DEFINER" width="100"></el-table-column>
              <el-table-column label="定义" prop="ROUTINE_DEFINITION" class-name="auto-ellipsis"
                               min-width="2"></el-table-column>
              <el-table-column label="创建时间" prop="CREATED" width="140" :formatter="formatTime"></el-table-column>
              <el-table-column label="最后修改时间" prop="LAST_ALTERED" width="140"
                               :formatter="formatTime"></el-table-column>
              <el-table-column label="备注" prop="ROUTINE_COMMENT" min-width="1"></el-table-column>
            </el-table>
          </pane>
          <pane>
            <cm readonly :code="selectedFunction.ROUTINE_DEFINITION" v-if="selectedFunction.ROUTINE_DEFINITION" />
          </pane>
        </splitpanes>
      </el-tab-pane>
      <el-tab-pane :label="`事件 (${events.rowsAffected || 0})`">
        <splitpanes horizontal>
          <pane>
            <el-table :data="computedEvent" height="100%" @row-click="(row) => (selectedEvent = row)" size="small"
                      border
                      stripe highlight-current-row>
              <el-table-column label="序号" type="index" align="center" width="60"></el-table-column>
              <el-table-column label="名称" prop="EVENT_NAME" width="200"></el-table-column>
              <el-table-column label="类型" prop="EVENT_TYPE" width="80"></el-table-column>
              <el-table-column label="状态" prop="STATUS" width="80"></el-table-column>
              <el-table-column label="周期" prop="INTERVAL_FIELD" width="80"
                               :formatter="formatEventInterval"></el-table-column>
              <el-table-column label="开始时间" prop="STARTS" width="140" :formatter="formatTime"></el-table-column>
              <el-table-column label="结束时间" prop="ENDS" width="140" :formatter="formatTime"></el-table-column>
              <el-table-column label="最后执行时间" prop="LAST_EXECUTED" width="140"
                               :formatter="formatTime"></el-table-column>
              <el-table-column label="创建时间" prop="CREATED" width="140" :formatter="formatTime"></el-table-column>
              <el-table-column label="最后修改时间" prop="LAST_ALTERED" width="140"
                               :formatter="formatTime"></el-table-column>
              <el-table-column label="备注" prop="EVENT_COMMENT"></el-table-column>
            </el-table>
          </pane>
          <pane>
            <cm readonly :code="selectedEvent.EVENT_DEFINITION" v-if="selectedEvent.EVENT_DEFINITION" />
          </pane>
        </splitpanes>
      </el-tab-pane>
      <el-tab-pane :label="`触发器 (${triggers.rowsAffected || 0})`">
        <splitpanes horizontal>
          <pane>
            <el-table :data="computedTrigger" height="100%" @row-click="(row) => (selectedTrigger = row)" size="small"
                      border stripe highlight-current-row>
              <el-table-column label="序号" type="index" align="center" width="60"></el-table-column>
              <el-table-column label="名称" prop="TRIGGER_NAME" width="200"></el-table-column>
              <el-table-column label="用户" prop="DEFINER" width="100"></el-table-column>
              <el-table-column label="表名" prop="EVENT_OBJECT_TABLE" width="200"></el-table-column>
              <el-table-column label="触发操作" prop="EVENT_MANIPULATION" width="60"></el-table-column>
              <el-table-column label="触发时机" prop="ACTION_TIMING" width="60"></el-table-column>
              <el-table-column label="执行顺序" prop="ACTION_ORDER" width="60"></el-table-column>
              <el-table-column label="执行条件" prop="ACTION_CONDITION" width="120"></el-table-column>
              <el-table-column label="执行内容" prop="ACTION_STATEMENT" class-name="auto-ellipsis"></el-table-column>
              <el-table-column label="创建时间" prop="CREATED" width="140" :formatter="formatTime"></el-table-column>
            </el-table>
          </pane>
          <pane>
            <cm readonly :code="selectedTrigger.ACTION_STATEMENT" v-if="selectedTrigger.ACTION_STATEMENT" />
          </pane>
        </splitpanes>
      </el-tab-pane>
      <el-tab-pane :label="`变量 (${variables.rowsAffected || 0})`">
        <el-table :data="computedVariable" height="100%" @row-click="(row) => (selectedView = row)" size="small" border
                  stripe highlight-current-row>
          <el-table-column label="序号" type="index" align="center" width="60"></el-table-column>
          <el-table-column label="变量名" prop="VARIABLE_NAME" width="300"></el-table-column>
          <el-table-column label="值" prop="VARIABLE_VALUE">
            <template #default="{ row }">
              <span v-html="(row.VARIABLE_VALUE || '').split(',').join('<br>')"></span>
            </template>
          </el-table-column>
        </el-table>
      </el-tab-pane>
    </el-tabs>
    <div class="db-not-connect-tip" v-else>未选择数据库</div>
  </div>
</template>

<script setup>
import Cm from '@/components/editor/Cm.vue'
// import SelectableList from "@/components/SelectableList.vue";
import TableColumns from '@/components/TableColumns.vue'
import { InfoFilled, Refresh } from '@element-plus/icons-vue'

function formatTime(row, col, val) {
  if (!val) {
    return ''
  }
  return new Date(val).toLocaleString()
}

function formatEventInterval(row) {
  return `${row.INTERVAL_VALUE} ${row.INTERVAL_FIELD}`
}
</script>
<script>
import { ElMessage, ElLoading } from 'element-plus'
import utils from '@/assets/scripts/utils'
import { mapGetters } from 'vuex'
import bus from '@/assets/scripts/bus'
import apis from '@/assets/apis'

export default {
  name: 'DatabaseInfo',
  data() {
    return {
      currentDatabaseName: null,
      tables: {
        data: [],
        rowsAffected: '-'
      },
      views: {
        data: [],
        rowsAffected: '-'
      },
      functions: {
        data: [],
        rowsAffected: '-'
      },
      events: {
        data: [],
        rowsAffected: '-'
      },
      triggers: {
        data: [],
        rowsAffected: '-'
      },
      variables: {},
      selectedTable: {},
      selectedView: {},
      selectedFunction: {},
      selectedEvent: {},
      selectedTrigger: {},
      selectedVariable: {},
      charset: '',
      loadTimer: -1,
      loading: false,
      filters: {
        name: ''
      },
      serverInfo: '-',
      tableDefinition: null,
      tableTabName: 'table',
      selectionTables: []
    }
  },
  watch: {
    computedTable() {
      this.$nextTick().then(() => {
        this.selectionTables.forEach(row => {
          this.$refs.tables.toggleRowSelection(row, true)
        })
      })
    }
  },
  mounted() {
    bus.on('database-selected', this.loadInfo)
  },
  beforeUnmount() {
    clearTimeout(this.loadTimer)
    bus.off('database-selected', this.loadInfo)
  },
  methods: {
    onTableSelect(selection, row) {
      const idx = this.selectionTables.findIndex(item => item.TABLE_NAME === row.TABLE_NAME)
      if (idx === -1) {
        this.selectionTables.push(row)
      } else {
        this.selectionTables.splice(idx, 1)
      }
    },
    onTableSelectAll(selection) {
      selection.forEach(row => {
        const idx = this.selectionTables.findIndex(item => item.TABLE_NAME === row.TABLE_NAME)
        if (idx === -1) {
          this.selectionTables.push(row)
        } else {
          this.selectionTables.splice(idx, 1)
        }
      })
    },
    onTableRowSelect(row) {
      this.selectedTable = row

      if (this.tableTabName === 'code') {
        this.loadTableDefinition()
      }
    },
    onTableTabClick(e) {
      if (e.paneName !== 'code') {
        return
      }
      this.loadTableDefinition()
    },
    loadTableDefinition() {
      this.tableDefinition = ''
      const tableName = this.selectedTable.TABLE_NAME
      if (!tableName) {
        return
      }
      this.$store.commit('updateGlobalMsg', '正在加载定义代码...')
      apis.dbm.table.getDefinition(tableName).then(data => {
        this.tableDefinition = data[0].data[0][1]
        this.$store.commit('updateGlobalMsg', '加载完成')
      }).catch(e => {
        this.$store.commit('updateGlobalMsg', `错误： ${e.message}`)
        ElMessage.error(e.message)
      }).finally(() => {
        this.loading = false
      })
    },
    loadInfo(e) {
      clearTimeout(this.loadTimer)
      this.loadTimer = setTimeout(() => {
        if (!this.activeInfo.connection) {
          return
        }
        let database
        if (e) {
          database = e.database
          if (this.currentDatabaseName === database) {
            return
          }
          this.currentDatabaseName = database
        } else {
          database = this.activeInfo.database?.name
        }
        // this.selectedEvent = {}
        // this.selectedFunction = {}
        // this.selectedTable = {}
        // this.selectedTrigger = {}
        // this.selectedVariable = {}
        // this.selectedView = {}
        this.$store.commit('updateGlobalMsg', '正在加载数据库信息...')
        this.loading = true
        apis.dbm.database.getInfo(this.activeInfo.connection, database).then((data) => {
          this.tables = utils.parseDatatable(data[0])
          this.views = utils.parseDatatable(data[1])
          this.functions = utils.parseDatatable(data[2])
          this.events = utils.parseDatatable(data[3])
          this.triggers = utils.parseDatatable(data[4])
          this.variables = utils.parseDatatable(data[5])

          const versionInfo = {
            version: '',
            comment: ''
          }

          this.variables.data.forEach((v) => {
            if (v.Variable_name) {
              v.VARIABLE_NAME = v.Variable_name
            }
            if (v.Value) {
              v.VARIABLE_VALUE = v.Value
            }
            if (v.VARIABLE_NAME === 'version') {
              versionInfo.version = v.VARIABLE_VALUE
            }
            if (v.VARIABLE_NAME === 'version_comment') {
              versionInfo.comment = v.VARIABLE_VALUE
            }
          })
          this.serverInfo = `服务器信息: ${versionInfo.comment} ${versionInfo.version}`
          this.charset = this.variables.data
            .filter(
              (item) =>
                item.VARIABLE_NAME === 'character_set_database' ||
                item.VARIABLE_NAME === 'collation_database'
            )
            .map((item) => item.VARIABLE_VALUE)
            .join('/')
          this.$store.commit('updateGlobalMsg', '加载完成')
        })
          .catch((e) => {
            this.$store.commit('updateGlobalMsg', `错误： ${e.message}`)
            ElMessage.error(e.message)
          })
          .finally(() => {
            this.loading = false
          })
      }, 200)
    },
    doOpenDataTable({ TABLE_NAME }) {
      const statement = `select * from ${TABLE_NAME}`
      bus.emit('open-table', {
        connection: this.activeInfo.connection.label,
        database: this.database.name,
        statement,
        table: TABLE_NAME
      })
    },
    doFilter(data, field) {
      const key = this.filters.name
      if (!key) {
        return data
      }
      return data.filter(item => item[field].toLowerCase().indexOf(key) !== -1)
    },
    async onExportDatabase() {
      const data = this.$refs.tables.getSelectionRows()
      if (!data.length) {
        ElMessage.warning('未选择要导出的表')
        return
      }
      const tables = data.map(item => item.TABLE_NAME)
      const loading = ElLoading.service({ text: '正在导出数据 ...' })
      apis.dbm.table.export(tables).catch(e => {
        ElMessage.warning(e.message)
      }).finally(() => {
        loading.close()
      })
    },
    async onExportDatabaseDoc() {
      const loading = ElLoading.service({ text: '正在生成文档 ...' })
      apis.dbm.table.exportDoc().catch(e => {
        ElMessage.warning(e.message)
      }).finally(() => {
        loading.close()
      })
    }
  },
  computed: {
    ...mapGetters({
      activeInfo: 'activeInfo'
    }),
    database() {
      return this.activeInfo.database
    },
    computedTable() {
      return this.doFilter(this.tables.data, 'TABLE_NAME')
    },
    computedView() {
      return this.doFilter(this.views.data, 'TABLE_NAME')
    },
    computedFunction() {
      return this.doFilter(this.functions.data, 'ROUTINE_NAME')
    },
    computedEvent() {
      return this.doFilter(this.events.data, 'EVENT_NAME')
    },
    computedTrigger() {
      return this.doFilter(this.triggers.data, 'TRIGGER_NAME')
    },
    computedVariable() {
      return this.doFilter(this.variables.data, 'VARIABLE_NAME')
    }
  }
}
</script>

<style lang="less" scoped>
.database-info {
  height: 100%;
  position: relative;
}

.base-info {
  padding: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #eeeeee;
}

.toolbar {
  display: flex;
}

.database--name {
  font-weight: bold;
  font-size: large;
  border: 1px solid #eaeaea;
  border-radius: 4px;
  padding: 5px 10px;
  background-color: #fafafa;
}

.database-meta {
  display: flex;
  align-items: center;
  font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono",
  "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace,
  serif;

  > div {
    margin-right: 20px;

    > span:nth-child(2) {
      padding: 0 2px;
      font-weight: bold;
    }
  }
}

.el-tabs.main-tab {
  position: absolute;
  left: 0;
  top: 60px;
  bottom: 0;
  width: 100%;
  background-color: #ffffff;

  > :deep(.el-tabs__content) {
    height: 100%;
  }
}

.el-tab-pane {
  height: 100%;
}

.meta-name {
  padding: 5px 15px;
  cursor: default;
  display: inline-block;

  &:hover {
    color: dodgerblue;
  }
}
</style>
<style lang="less">
.db-not-connect-tip {
  text-align: center;
  padding-top: 40px;
  font-size: 2.4em;
  color: #aaaaaa;
}

.var-item {
  display: flex;
  align-items: center;
  justify-content: flex-start;

  .var-name {
  }

  .var-eq {
    color: #aaaaaa;
  }

  .var-value {
    color: #e743b5;
    max-width: 400px;
    display: inline-block;
    word-wrap: break-word;
  }
}
</style>
